package com.gitee.qdbp.vmall.sales.biz.goods.main.service;

import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.ordering.OrderPaging;
import com.gitee.qdbp.able.jdbc.paging.PageList;
import com.gitee.qdbp.able.jdbc.paging.Paging;
import com.gitee.qdbp.able.model.reusable.EditResult;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.base.system.model.IAccount;
import com.gitee.qdbp.general.common.api.sequence.service.IStrongSequenceGenerator;
import com.gitee.qdbp.general.common.enums.VersionState;
import com.gitee.qdbp.tools.specialized.KeywordHandler;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.JsonTools;
import com.gitee.qdbp.tools.utils.VerifyTools;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.GoodsOptions;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.GoodsPriceBean;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.GoodsVersionBean;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.GoodsVersionUpdate;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.GoodsVersionWhere;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.PriceSingleParams;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.PublishSingleParams;
import com.gitee.qdbp.vmall.sales.api.goods.main.model.QuantitySingleParams;
import com.gitee.qdbp.vmall.sales.api.goods.main.service.IGoodsVersionExecutor;
import com.gitee.qdbp.vmall.sales.api.goods.manage.model.InventoryRealtimeBean;
import com.gitee.qdbp.vmall.sales.api.goods.manage.model.InventoryRealtimeUpdate;
import com.gitee.qdbp.vmall.sales.api.goods.manage.model.InventoryRealtimeWhere;
import com.gitee.qdbp.vmall.sales.biz.goods.main.basic.GoodsVersionBasic;
import com.gitee.qdbp.vmall.sales.biz.goods.manage.basic.InventoryRealtimeBasic;
import com.gitee.qdbp.vmall.sales.biz.goods.manage.model.AddSalesQuantityParams;
import com.gitee.qdbp.vmall.sales.biz.goods.manage.service.SalesSummingExecutor;
import com.gitee.qdbp.vmall.sales.enums.GoodsState;
import com.gitee.qdbp.vmall.sales.enums.MallSequence;
import com.gitee.qdbp.vmall.sales.error.MallErrorCode;

/**
 * 商品版本信息业务处理类
 *
 * @author zhh
 * @version 170706
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public class GoodsVersionExecutor implements IGoodsVersionExecutor {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(GoodsVersionExecutor.class);

    /** 商品版本信息DAO **/
    @Autowired
    private GoodsVersionBasic goodsVersionBasic;
    /** 实时库存DAO **/
    @Autowired
    private InventoryRealtimeBasic inventoryRealtimeBasic;
    /** 销量处理类 **/
    @Autowired
    private SalesSummingExecutor salesSummingExecutor;

    @Autowired
    private IStrongSequenceGenerator sequenceGenerator;

    public GoodsVersionBean createDuplicate(String goodsVid, IAccount operator) throws ServiceException {
        String msg = "Failed to create GoodsVersion Duplicate. ";

        if (VerifyTools.isBlank(operator)) {
            log.trace(msg + "params is null: operator");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(goodsVid)) {
            log.trace(msg + "params is null: goodsVid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        GoodsVersionBean older = findByVidThrowOnNotExists(goodsVid);
        return doCreateDuplicate(older, null, operator);
    }

    private GoodsVersionBean doCreateDuplicate(GoodsVersionBean older, GoodsPriceBean params, IAccount operator)
            throws ServiceException {

        String newVid = sequenceGenerator.generate(MallSequence.GOODS_INFO);
        int editIndex = 0;
        older.setVid(newVid);
        older.setGoodsState(GoodsState.PENDING); // 商品状态
        older.setVersionState(VersionState.DUPLICATE); // 版本状态
        older.setEditIndex(editIndex);
        older.setCreatorId(operator.getId()); // 创建人ID
        older.setCreateTime(null);
        older.setPublishTime(null);
        older.setSubmitDesc(null);
        if (params != null) {
            older.setMarketPriceText(params.getMarketPriceText());
            older.setSalesPriceText(params.getSalesPriceText());
            older.setPriceValue(params.getPriceValue());
        }

        // 向vml_goods_version表插入记录
        goodsVersionBasic.create(older);

        return older;
    }

    @Override
    public EditResult save(GoodsVersionBean model, IAccount operator) throws ServiceException {
        String msg = "Failed to save GoodsVersion. ";

        if (VerifyTools.isBlank(operator)) {
            log.trace(msg + "params is null: operator");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model)) {
            log.trace(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getTitle())) {
            model.setTitle(model.getName());
        }

        // 保存草稿时绝大部分字段都可以为空

        if (VerifyTools.isBlank(model.getVid())) { // 新增(创建新商品)
            // 设置初始状态
            String goodsUid = sequenceGenerator.generate(MallSequence.GOODS_INFO);
            String goodsVid = sequenceGenerator.generate(MallSequence.GOODS_INFO);

            int editIndex = 0;
            model.setUid(goodsUid);
            model.setVid(goodsVid);
            model.setGoodsState(GoodsState.PENDING); // 商品状态
            model.setVersionState(VersionState.ACTIVATED); // 版本状态
            model.setCreatorId(operator.getId()); // 创建人ID
            model.setEditIndex(editIndex);

            KeywordHandler keywords = KeywordHandler.newInstance();
            keywords.addText(model.getName(), model.getTitle(), model.getIntroText());
            keywords.addPlain(model.getModelNumber());
            model.setQueryKeywords(keywords.toString());

            // 向vml_goods_version表插入记录
            goodsVersionBasic.create(model);

            return new EditResult(goodsVid, editIndex);
        } else {
            String goodsVid = model.getVid();
            Integer editIndex = model.getEditIndex();
            if (VerifyTools.isBlank(editIndex)) {
                log.trace(msg + "params is null: EditIndex");
                throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
            }

            GoodsVersionBean older = findByVidThrowOnNotExists(goodsVid);
            // 能查到但不能编辑别人的记录, 逻辑有点奇怪, 前台要做很多处理才能合理, 干脆不控制了
            // if (!older.getCreatorId().equals(operator.getUserId())) {
            //     String fmt = msg + "Doesn't belong to oneself. goodsVid={}, creator={}, operator={}.";
            //     log.error(fmt, goodsVid, older.getCreatorId(), operator);
            //     // 不允许编辑其他人的记录
            //     throw new ServiceException(MallErrorCode.EDIT_BY_NOT_ONESELF);
            // }

            // 如果[编辑序号]有变更, 说明已被编辑过, 如果继续保存, 将会覆盖之前修改的内容
            int oldEditIndex = older.getEditIndex();
            if (!editIndex.equals(oldEditIndex)) {
                log.error(msg + "edit index changed. [{}!=db:{}]. goodsVid={}.", editIndex, oldEditIndex, goodsVid);
                // 记录在提交前已被他人编辑
                throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
            }
            // 只有未提交和已驳回状态的允许编辑
            GoodsState approveState = older.getGoodsState();
            if (VerifyTools.isNotExists(approveState, GoodsState.PENDING, GoodsState.REJECTED)) {
                log.error(msg + "approve state [{}] can't edit. goodsVid={}.", older.getGoodsState(), goodsVid);
                // 记录处于不允许编辑状态
                throw new ServiceException(MallErrorCode.EDIT_BY_ERROR_APPROVE_STATE);
            }

            GoodsVersionUpdate newer = createChangedModel(model.to(GoodsVersionUpdate.class), older);

            if (newer == null) {
                return new EditResult(goodsVid, editIndex);
            } else {
                newer.setVid(null);
                newer.setEditIndexAdd(1); // 每编辑一次递增1
                GoodsVersionWhere where = newer.getWhere(true);
                where.setVid(goodsVid);
                where.setEditIndex(model.getEditIndex()); // where条件中带上原序号
                where.setGoodsState(approveState);

                // 更新vml_goods_version表的记录
                int rows = goodsVersionBasic.update(newer, false);
                if (rows == 0) {
                    log.error(msg + "affected rows is 0. goodsVid={}.", goodsVid);
                    // 记录在提交前已被编辑
                    throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
                }

                return new EditResult(goodsVid, editIndex + 1);
            }
        }
    }

    public void submit(GoodsVersionBean model, String description, IAccount operator) throws ServiceException {
        String msg = "Failed to submit GoodsVersion. ";

        // 检查参数
        checkSubmitParams(model, operator);
        // 保存草稿
        EditResult result = save(model, operator);

        // 组装提交参数
        GoodsVersionUpdate ud = new GoodsVersionUpdate();
        ud.setEditIndexAdd(1); // 每编辑一次递增1
        ud.setGoodsState(GoodsState.SUBMITTED);
        GoodsVersionWhere where = ud.getWhere(true);
        where.setVid(result.getId());
        where.setEditIndex(result.getEditIndex());
        where.addGoodsState(GoodsState.PENDING, GoodsState.REJECTED); // 未提交和已驳回的允许提交

        // 更新vml_goods_version表的记录
        int rows = goodsVersionBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. goodsVid={}.", result.getId());
            // 记录在提交前已被编辑
            throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
        }

        // TODO description add to ProcessingRecord
    }

    private void checkSubmitParams(GoodsVersionBean model, IAccount operator) throws ServiceException {
        String msg = "Failed to submit GoodsVersion. ";

        if (VerifyTools.isBlank(operator)) {
            log.trace(msg + "params is null: operator");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model)) {
            log.trace(msg + "params is null: model");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getName())) {
            log.trace(msg + "params is null: name");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getName())) {
            log.trace(msg + "params is null: name");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getTitle())) {
            model.setTitle(model.getName());
        }
        if (VerifyTools.isBlank(model.getPriceValue())) {
            log.trace(msg + "params is null: priceValue");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(model.getDescDetails())) {
            log.trace(msg + "params is null: descDetails");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
    }

    /** 审批 **/
    public void approve(String goodsVid, boolean pass, String description, IAccount operator) throws ServiceException {
        String msg = "Failed to approve GoodsVersion. ";
        if (VerifyTools.isBlank(goodsVid)) {
            log.error(msg + "params is null: goodsVid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        GoodsVersionBean older = findByVidThrowOnNotExists(goodsVid);
        GoodsState state = older.getGoodsState();
        if (state != GoodsState.SUBMITTED) {
            log.error(msg + "record state error. goodsVid={}, state={}", goodsVid, state);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // 组装提交参数
        GoodsVersionUpdate ud = new GoodsVersionUpdate();
        if (VerifyTools.isNotBlank(description)) {
            GoodsOptions options = older.getOptions(true);
            options.setApproveDesc(description);
            ud.setOptions(options);
        }
        if (pass) {
            ud.setGoodsState(GoodsState.ARGEED);
        } else {
            ud.setGoodsState(GoodsState.REJECTED);
        }

        GoodsVersionWhere where = ud.getWhere(true);
        where.setVid(goodsVid);
        where.setGoodsState(GoodsState.SUBMITTED);

        // 更新vml_goods_version表的记录
        int rows = goodsVersionBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. goodsVid={}.", goodsVid);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    /** 发布上架(只允许发布已审核或已下架的)(如果是已下架版本重新发布且价格有调整, 则自动生成新的副本并发布上架) **/
    @Override
    public EditResult publish(PublishSingleParams params, IAccount operator) throws ServiceException {
        String msg = "Failed to publish GoodsVersion. ";
        String goodsVid = params.getVid();
        if (VerifyTools.isBlank(goodsVid)) {
            log.error(msg + "params is null: goodsVid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        GoodsVersionBean older = findByVidThrowOnNotExists(goodsVid);
        GoodsState goodsState = older.getGoodsState();
        // 只允许发布已审核或已下架的
        if (goodsState != GoodsState.ARGEED && goodsState != GoodsState.PAUSING) {
            log.error(msg + "record state error. goodsVid={}, state={}", goodsVid, goodsState);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }
        if (older.getSkuInstanceData() != null) {
            log.error(msg + "unsupported publish complex goods by PublishSingleParams. goodsVid={}", goodsVid);
            throw new ServiceException(ResultCode.UNSUPPORTED_OPERATION);
        }

        GoodsVersionUpdate ud = createPriceModel(params, older);
        if (goodsState == GoodsState.PAUSING && ud != null) {
            // 如果是已下架版本重新发布且价格有调整, 则自动生成新的副本并发布上架
            // 生成新的副本
            GoodsVersionBean newer = doCreateDuplicate(older, (GoodsPriceBean) params, operator);
            // 直接发布上架, 价格在生成副本时已经改过了, 所以new一个对象, 只保留销量和库存
            PublishSingleParams temp = new PublishSingleParams();
            temp.setVid(newer.getVid());
            temp.setSalesQuantityAdd(params.getSalesQuantityAdd());
            temp.setStockQuantityAdd(params.getStockQuantityAdd());
            doPublish(temp, older, false, operator);
            return new EditResult(newer.getVid(), newer.getEditIndex());
        } else {
            int editIndex = older.getEditIndex();
            if (ud != null) {
                ud.setEditIndex(editIndex++);
                GoodsVersionWhere where = ud.getWhere(true);
                where.setVid(goodsVid);
                where.setEditIndex(older.getEditIndex());
                where.setGoodsState(older.getGoodsState());
                where.setVersionState(older.getVersionState());
                goodsVersionBasic.update(ud, true);
            }
            doPublish(params, older, true, operator);
            return new EditResult(goodsVid, editIndex);
        }
    }

    private void doPublish(PublishSingleParams params, GoodsVersionBean older, boolean checkState, IAccount operator)
            throws ServiceException {
        String msg = "Failed to publish GoodsVersion. ";

        String goodsVid = params.getVid();
        String goodsUid = older.getUid();
        { // 先将该商品在售的其他版本改为下架
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setGoodsState(GoodsState.PAUSING);
            // 是改为DUPLICATE还是ENDED呢?
            ud.setVersionState(VersionState.DUPLICATE);
            GoodsVersionWhere where = ud.getWhere(true);
            where.setUid(goodsUid);
            where.setGoodsState(GoodsState.SELLING);
            where.setVersionState(VersionState.ACTIVATED);
            goodsVersionBasic.update(ud, false);
        }
        { // 再将该商品其他的ACTIVATED改为DUPLICATE, 确保只有一个ACTIVATED版本
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setVersionState(VersionState.DUPLICATE);
            GoodsVersionWhere where = ud.getWhere(true);
            where.setUid(goodsUid);
            where.setVersionState(VersionState.ACTIVATED);
            goodsVersionBasic.update(ud, false);
        }

        Integer salesQuantity = params.getSalesQuantityAdd();
        Integer stockQuantity = params.getStockQuantityAdd();
        { // 最后将当前版本改为上架 
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setGoodsState(GoodsState.SELLING);
            ud.setVersionState(VersionState.ACTIVATED);
            ud.setPublishTimeToCurrent(true);
            if (salesQuantity != null) {
                ud.setSalesQuantityTotalAdd(salesQuantity);
            }
            if (stockQuantity != null) {
                ud.setStockQuantityAdd(stockQuantity);
            }
            GoodsVersionWhere where = ud.getWhere(true);
            where.setVid(goodsVid);
            if (checkState) {
                where.addGoodsState(GoodsState.ARGEED, GoodsState.PAUSING);
            }

            // 更新vml_goods_version表的记录
            int rows = goodsVersionBasic.update(ud, false);
            if (rows == 0) {
                log.error(msg + "affected rows is 0. goodsVid={}.", goodsVid);
                throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
            }
        }

        { // 检查实时库存表有没有记录
            InventoryRealtimeWhere where = new InventoryRealtimeWhere();
            where.setGoodsUid(goodsUid);
            where.setSkuId(goodsUid); // 无规格的商品SkuId=GoodsUid
            InventoryRealtimeBean inventory = inventoryRealtimeBasic.find(where);
            if (inventory == null) { // 创建实时库存记录
                inventory = new InventoryRealtimeBean();
                inventory.setTenantCode(older.getTenantCode());
                inventory.setGoodsUid(goodsUid);
                inventory.setSkuId(goodsUid); // 无规格的商品SkuId=GoodsUid
                inventory.setStockQuantity(stockQuantity == null ? 0 : stockQuantity);
                inventory.setSoldQuantity(0);
                inventoryRealtimeBasic.create(inventory);
            } else { // 修改实时库存数量
                if (stockQuantity != null && !stockQuantity.equals(inventory.getStockQuantity())) {
                    InventoryRealtimeUpdate up = new InventoryRealtimeUpdate();
                    up.setStockQuantityAdd(stockQuantity);
                    up.setId(inventory.getId());
                    inventoryRealtimeBasic.update(up, false);
                }
            }
        }

        if (salesQuantity != null) { // 增加初始销售量
            AddSalesQuantityParams p = new AddSalesQuantityParams();
            p.setFictitious(true); // 虚拟销量
            p.setTenantCode(older.getTenantCode());
            p.setSkuId(goodsUid); // 无规格的商品SkuId=GoodsUid
            p.setSalesTime(new Date());
            p.setQuantity(params.getSalesQuantityAdd());
            salesSummingExecutor.add(p, operator);
        }

    }

    /** 下架停售 **/
    @Override
    public void unpublish(String goodsVid, String description, IAccount operator) throws ServiceException {
        String msg = "Failed to unpublish GoodsVersion. ";
        // 组装提交参数
        GoodsVersionUpdate ud = new GoodsVersionUpdate();
        ud.setGoodsState(GoodsState.PAUSING);
        GoodsVersionWhere where = ud.getWhere(true);
        where.setVid(goodsVid);
        where.setGoodsState(GoodsState.SELLING);

        // 更新vml_goods_version表的记录
        int rows = goodsVersionBasic.update(ud, false);
        if (rows == 0) {
            log.error(msg + "affected rows is 0. goodsVid={}.", goodsVid);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        // TODO description add to ProcessingRecord
    }

    /** 根据版本ID查找商品, 如果不存在则报错 **/
    private GoodsVersionBean findByVidThrowOnNotExists(String goodsVid) throws ServiceException {

        GoodsVersionWhere model = new GoodsVersionWhere();
        model.setVid(goodsVid);

        GoodsVersionBean bean = goodsVersionBasic.find(model);

        if (bean == null) {
            log.warn("Goods version info not found, goodsVid=" + goodsVid);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }
        return bean;
    }

    @Override
    public void delete(String goodsVid, String description, IAccount operator) throws ServiceException {
        String msg = "Failed to delete GoodsVersion. ";

        if (VerifyTools.isBlank(operator)) {
            log.error(msg + "params is null: operator");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(goodsVid)) {
            log.error(msg + "params is null: goodsVid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        // 从vml_goods_version表查询原记录
        GoodsVersionBean older = goodsVersionBasic.findByVid(goodsVid);
        if (older == null) {
            log.error(msg + "record is not found.\n\tgoodsVid is " + goodsVid);
            throw new ServiceException(ResultCode.RECORD_NOT_EXIST);
        }

        GoodsState state = older.getGoodsState();
        if (state == GoodsState.SELLING || state == GoodsState.PAUSING) {
            // 曾经发布上架过的不能删除,只将版本状态改为ENDED(因为查看订单快照时需要引用)
            // 组装提交参数
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setVersionState(VersionState.ENDED);
            if (state == GoodsState.SELLING) { // 已上架的需要改为已下架
                ud.setGoodsState(GoodsState.PAUSING);
            }
            GoodsVersionWhere where = ud.getWhere(true);
            where.setVid(goodsVid);

            // 更新vml_goods_version表的记录
            int rows = goodsVersionBasic.update(ud, false);
            if (rows == 0) {
                log.error(msg + "affected rows is 0. goodsVid={}.", goodsVid);
                // 记录在提交前已被编辑
                throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
            }
        } else {
            // 从未发布上线过的直接删除
            // 删除vml_goods_version表的记录
            GoodsVersionWhere where = new GoodsVersionWhere();
            where.setVids(ConvertTools.toList(goodsVid));
            where.addGoodsState(GoodsState.PENDING, GoodsState.SUBMITTED, GoodsState.ARGEED, GoodsState.REJECTED);
            goodsVersionBasic.delete(where, false);
        }

        if (older.getVersionState() == VersionState.ACTIVATED) {
            // 删除的是正本, 则从副本中选择最新的一个版本提升为正本
            GoodsVersionWhere where = new GoodsVersionWhere();
            where.setUid(older.getUid());
            where.setVersionState(VersionState.DUPLICATE);
            OrderPaging paging = OrderPaging.of(new Paging(1, 1), "createTime desc");
            PageList<GoodsVersionBean> paged = goodsVersionBasic.list(where, paging);
            if (VerifyTools.isNotBlank(paged)) {
                GoodsVersionBean bean = paged.get(0);
                GoodsVersionUpdate ud = new GoodsVersionUpdate();
                ud.setVersionState(VersionState.ACTIVATED);
                ud.getWhere(true).setVid(bean.getVid());
                goodsVersionBasic.update(ud, false);
            }
        }
        // TODO description add to ProcessingRecord
    }

    /** 补充库存 **/
    @Override
    public void updateStockQuantity(QuantitySingleParams params, IAccount operator) throws ServiceException {
        String goodsUid = params.getUid();
        Integer quantityAdd = params.getQuantityAdd();
        String msg = "Failed to update GoodsStockQuantity. ";
        if (VerifyTools.isBlank(goodsUid)) {
            log.error(msg + "params is null: goodsUid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(quantityAdd)) {
            log.error(msg + "params is null: quantityAdd");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (quantityAdd == 0) {
            return;
        }
        { // 更新库存表
            InventoryRealtimeUpdate up = new InventoryRealtimeUpdate();
            up.setStockQuantityAdd(quantityAdd);
            InventoryRealtimeWhere w = up.getWhere(true);
            w.setGoodsUid(goodsUid); // 商品版本ID
            w.setSkuId(goodsUid); // 单一商品的SkuId=GoodsUid
            int rows = inventoryRealtimeBasic.update(up, false);
            if (rows == 0) {
                InventoryRealtimeBean bean = new InventoryRealtimeBean();
                bean.setGoodsUid(goodsUid); // 商品版本ID
                bean.setSkuId(goodsUid); // 单一商品的SkuId=GoodsUid
                bean.setStockQuantity(quantityAdd); // 可售库存量
                bean.setSoldQuantity(0); // 已售库存量(待发货)
                inventoryRealtimeBasic.create(bean);
            }
        }
        { // 更新商品表
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setStockQuantityAdd(quantityAdd);
            ud.getWhere(true).setUid(goodsUid);
            goodsVersionBasic.update(ud, false);
        }
    }

    /** 调整销量 **/
    @Override
    public void updateSalesQuantity(QuantitySingleParams params, IAccount operator) throws ServiceException {
        String goodsUid = params.getUid();
        Integer quantityAdd = params.getQuantityAdd();
        String msg = "Failed to update GoodsSalesQuantity. ";
        if (VerifyTools.isBlank(goodsUid)) {
            log.error(msg + "params is null: goodsUid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        { // 更新库存表
            AddSalesQuantityParams p = new AddSalesQuantityParams();
            p.setFictitious(true); // 虚拟销量
            p.setSkuId(goodsUid); // 单一商品的SkuId=GoodsUid
            p.setSalesTime(new Date());
            p.setQuantity(quantityAdd);
            salesSummingExecutor.add(p, operator);
        }
        { // 更新商品表
            GoodsVersionUpdate ud = new GoodsVersionUpdate();
            ud.setSalesQuantityTotalAdd(quantityAdd);
            ud.getWhere(true).setUid(goodsUid);
            goodsVersionBasic.update(ud, false);
        }
    }

    /** 修改价格(只允许修改未发布上架的商品) **/
    @Override
    public EditResult editPrice(PriceSingleParams params, IAccount operator) throws ServiceException {
        String msg = "Failed to EditGoodsPrice. ";

        String goodsVid = params.getVid();
        GoodsVersionBean older = checkUpdatePriceParams(msg, params, operator);
        GoodsState goodsState = older.getGoodsState();
        if (goodsState == GoodsState.SELLING || goodsState == GoodsState.PAUSING) {
            log.error(msg + "record state error. goodsVid={}, state={}", goodsVid, goodsState);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        GoodsVersionUpdate ud = createPriceModel(params, older);
        if (ud == null) {
            return new EditResult(goodsVid, params.getEditIndex());
        } else {
            ud.setEditIndex(params.getEditIndex() + 1);
            GoodsVersionWhere where = ud.getWhere(true);
            where.setVid(params.getVid());
            where.setEditIndex(params.getEditIndex());
            where.setGoodsState(older.getGoodsState());
            where.setVersionState(older.getVersionState());

            int rows = goodsVersionBasic.update(ud, false);
            if (rows > 0) {
                return new EditResult(goodsVid, ud.getEditIndex());
            } else {
                log.error(msg + "affected rows is 0. goodsVid={}.\n\t{}", goodsVid, JsonTools.toJsonString(ud));
                // 记录在提交前已被编辑
                throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
            }
        }
    }

    /**
     * 调整价格(已发布上架的商品, 自动生成新的副本并直接发布上架)
     * 
     * @throws ServiceException
     **/
    @Override
    public EditResult changePrice(PriceSingleParams params, IAccount operator) throws ServiceException {
        String msg = "Failed to ChangeGoodsPrice. ";

        String goodsVid = params.getVid();
        GoodsVersionBean older = checkUpdatePriceParams(msg, params, operator);
        GoodsState goodsState = older.getGoodsState();
        if (goodsState != GoodsState.SELLING) {
            log.error(msg + "record state error. goodsVid={}, state={}", goodsVid, goodsState);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }

        GoodsVersionUpdate ud = createPriceModel(params, older);
        if (ud == null) { // 没有修改任何内容
            return new EditResult(goodsVid, params.getEditIndex());
        } else {
            // 生成新的副本
            GoodsVersionBean newer = doCreateDuplicate(older, params, operator);
            // 直接发布上架, 价格在生成副本时已经改过了, 所以新对象不需要价格字段
            PublishSingleParams temp = new PublishSingleParams();
            temp.setVid(newer.getVid());
            doPublish(temp, older, false, operator);

            return new EditResult(newer.getVid(), newer.getEditIndex());
        }
    }

    private GoodsVersionBean checkUpdatePriceParams(String msg, PriceSingleParams params, IAccount operator)
            throws ServiceException {

        if (VerifyTools.isBlank(params)) {
            log.error(msg + "params is null: params");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        String goodsVid = params.getVid();
        if (VerifyTools.isBlank(goodsVid)) {
            log.error(msg + "params is null: goodsVid");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(params.getEditIndex())) {
            log.error(msg + "params is null: EditIndex");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(params.getPriceValue())) {
            log.error(msg + "params is null: PriceValue");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        GoodsVersionBean older = findByVidThrowOnNotExists(goodsVid);
        if (VerifyTools.notEquals(params.getEditIndex(), older.getEditIndex())) {
            String m = msg + "edit index changed. goodsVid={}. Params:{} != DB:{}.";
            log.error(m, params.getEditIndex(), older.getEditIndex());
            // 记录在提交前已被编辑
            throw new ServiceException(MallErrorCode.EDIT_BY_DIRTY_READ);
        }
        VersionState versionState = older.getVersionState();
        if (versionState == VersionState.ENDED) {
            log.error(msg + "record state error. goodsVid={}, state={}", goodsVid, versionState);
            throw new ServiceException(ResultCode.RECORD_STATE_ERROR);
        }
        return older;
    }

    private GoodsVersionUpdate createPriceModel(GoodsPriceBean params, GoodsVersionBean older) throws ServiceException {
        GoodsVersionUpdate ud = new GoodsVersionUpdate();
        boolean changed = false;
        if (notEquals(params.getPriceValue(), older.getPriceValue())) {
            changed = true;
            ud.setPriceValue(params.getPriceValue()); // 价格值(实际售价)
        }
        if (notEquals(params.getMarketPriceText(), older.getMarketPriceText())) {
            changed = true;
            if (VerifyTools.isBlank(params.getMarketPriceText())) {
                ud.setMarketPriceTextToNull(true);
            } else {
                ud.setMarketPriceText(params.getMarketPriceText()); // 市场价格描述
            }
        }
        if (notEquals(params.getSalesPriceText(), older.getSalesPriceText())) {
            changed = true;
            if (VerifyTools.isBlank(params.getMarketPriceText())) {
                ud.setSalesPriceTextToNull(true);
            } else {
                ud.setSalesPriceText(params.getSalesPriceText()); // 销售价格描述(用于主商品展示的价格描述, 如80~99,199起)
            }
        }
        return changed ? ud : null;
    }

    private boolean notEquals(Object o, Object n) {
        return VerifyTools.notEquals(o, n) && !VerifyTools.isAllBlank(o, n);
    }

    /**
     * 创建一个新的对象, 只包含改动过的字段
     *
     * @author zhh
     * @param model 目标对象(一般是参数传入的)
     * @param older 源对象(一般是从数据库查询得到的)
     * @return 只包含有更新的字段对象
     */
    private GoodsVersionUpdate createChangedModel(GoodsVersionUpdate model, GoodsVersionBean older) {
        GoodsVersionUpdate newer = new GoodsVersionUpdate();
        newer.setWhere(model.getWhere());

        boolean changed = false;
        newer.setVid(model.getVid()); // 商品版本ID

        // if (VerifyTools.isChanged(model.getUid(), older.getUid())) {
        //     changed = true;
        //     newer.setUid(model.getUid()); // 商品唯一ID
        // }
        // if (VerifyTools.isChanged(model.getTenantCode(), older.getTenantCode())) {
        //     changed = true;
        //     newer.setTenantCode(model.getTenantCode()); // 租户编号
        // }
        // if (VerifyTools.isChanged(model.getDeptCode(), older.getDeptCode())) {
        //     changed = true;
        //     newer.setDeptCode(model.getDeptCode()); // 部门编号
        // }
        if (VerifyTools.isChanged(model.getCategoryCode(), older.getCategoryCode())) {
            changed = true;
            newer.setCategoryCode(model.getCategoryCode()); // 分类编号
        }
        if (VerifyTools.isChanged(model.getBrandCode(), older.getBrandCode())) {
            changed = true;
            newer.setBrandCode(model.getBrandCode()); // 品牌ID
        }
        if (VerifyTools.isChanged(model.getModelNumber(), older.getModelNumber())) {
            changed = true;
            newer.setModelNumber(model.getModelNumber()); // 型号
        }
        if (VerifyTools.isChanged(model.getName(), older.getName())) {
            changed = true;
            newer.setName(model.getName()); // 商品名称
        }
        if (VerifyTools.isChanged(model.getTitle(), older.getTitle())) {
            changed = true;
            newer.setTitle(model.getTitle()); // 标题
        }
        if (VerifyTools.isChanged(model.getUnit(), older.getUnit())) {
            changed = true;
            newer.setUnit(model.getUnit()); // 单位(个/件/台/袋等)
        }
        if (VerifyTools.isChanged(model.getImageInfo(), older.getImageInfo())) {
            changed = true;
            newer.setImageInfo(model.getImageInfo()); // 图片信息
        }
        if (VerifyTools.isChanged(model.getMarketPriceText(), older.getMarketPriceText())) {
            changed = true;
            newer.setMarketPriceText(model.getMarketPriceText()); // 市场价格描述
        }
        if (VerifyTools.isChanged(model.getSalesPriceText(), older.getSalesPriceText())) {
            changed = true;
            newer.setSalesPriceText(model.getSalesPriceText()); // 销售价格描述(用于主商品展示的价格描述, 如80~99,199起)
        }
        if (VerifyTools.isChanged(model.getPriceValue(), older.getPriceValue())) {
            changed = true;
            newer.setPriceValue(model.getPriceValue()); // 价格值(实际售价)
        }
        // if (VerifyTools.isChanged(model.getSalesQuantityTotal(), older.getSalesQuantityTotal())) {
        //     changed = true;
        //     newer.setSalesQuantityTotal(model.getSalesQuantityTotal()); // 总销量
        // }
        // if (VerifyTools.isChanged(model.getStockQuantity(), older.getStockQuantity())) {
        //     changed = true;
        //     newer.setStockQuantity(model.getStockQuantity()); // 库存量
        // }
        if (VerifyTools.isChanged(model.getIntroText(), older.getIntroText())) {
            changed = true;
            newer.setIntroText(model.getIntroText()); // 摘要
        }
        if (VerifyTools.isChanged(model.getDescDetails(), older.getDescDetails())) {
            changed = true;
            newer.setDescDetails(model.getDescDetails()); // 详细描述(富文本)
        }
        // if (VerifyTools.isChanged(model.getSortIndex(), older.getSortIndex())) {
        //     changed = true;
        //     newer.setSortIndex(model.getSortIndex()); // 排序号
        // }
        // if (VerifyTools.isChanged(model.getSpecificKindId(), older.getSpecificKindId())) {
        //     changed = true;
        //     newer.setSpecificKindId(model.getSpecificKindId()); // 规格分类ID
        // }
        // if (VerifyTools.isChanged(model.getSpecificKindData(), older.getSpecificKindData())) {
        //     changed = true;
        //     newer.setSpecificKindData(model.getSpecificKindData()); // 规格数据列表(GoodsSpecificKind)
        // }
        // if (VerifyTools.isChanged(model.getSkuInstanceData(), older.getSkuInstanceData())) {
        //     changed = true;
        //     newer.setSkuInstanceData(model.getSkuInstanceData()); // 单品实例列表(SkuSpecificInstance)
        // }
        // if (VerifyTools.isChanged(model.getCreatorId(), older.getCreatorId())) {
        //     changed = true;
        //     newer.setCreatorId(model.getCreatorId()); // 创建人ID
        // }
        // if (VerifyTools.isChanged(model.getCreateTime(), older.getCreateTime())) {
        //     changed = true;
        //     newer.setCreateTime(model.getCreateTime()); // 创建时间
        // }
        // if (VerifyTools.isChanged(model.getPublishTime(), older.getPublishTime())) {
        //     changed = true;
        //     newer.setPublishTime(model.getPublishTime()); // 发布时间
        // }
        // if (VerifyTools.isChanged(model.getExpireTime(), older.getExpireTime())) {
        //     changed = true;
        //     newer.setExpireTime(model.getExpireTime()); // 过期时间
        // }
        if (VerifyTools.isChanged(model.getOptions(), older.getOptions())) {
            changed = true;
            newer.setOptions(model.getOptions()); // 选项
        }
        // if (VerifyTools.isChanged(model.getSubmitDesc(), older.getSubmitDesc())) {
        //     changed = true;
        //     newer.setSubmitDesc(model.getSubmitDesc()); // 提交说明
        // }
        // if (VerifyTools.isChanged(model.getEditIndex(), older.getEditIndex())) {
        //     changed = true;
        //     newer.setEditIndex(model.getEditIndex()); // 编辑序号(每编辑一次递增1)
        // }
        // if (VerifyTools.isChanged(model.getGoodsState(), older.getGoodsState())) {
        //     changed = true;
        //     newer.setGoodsState(model.getGoodsState()); // 商品状态(0.未提交|1.已提交|2.已审核|3.已驳回|4.已上架|5.已下架)
        // }
        // if (VerifyTools.isChanged(model.getVersionState(), older.getVersionState())) {
        //     changed = true;
        //     newer.setVersionState(model.getVersionState()); // 版本状态(0.正本|1.副本|2.归档)
        // }
        // if (VerifyTools.isChanged(model.getQueryKeywords(), older.getQueryKeywords())) {
        //     changed = true;
        //     newer.setQueryKeywords(model.getQueryKeywords()); // 查询关键字
        // }
        // if (VerifyTools.isChanged(model.getDataState(), older.getDataState())) {
        //     changed = true;
        //     newer.setDataState(model.getDataState()); // 数据状态:0为正常|其他为删除
        // }
        // if (Boolean.TRUE.equals(model.isUidToNull())) {
        //     changed = true;
        //     newer.setUidToNull(true); // 商品唯一ID更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isTenantCodeToNull())) {
        //     changed = true;
        //     newer.setTenantCodeToNull(true); // 租户编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isDeptCodeToNull())) {
        //     changed = true;
        //     newer.setDeptCodeToNull(true); // 部门编号更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isCategoryCodeToNull())) {
        //     changed = true;
        //     newer.setCategoryCodeToNull(true); // 分类编号更新为空值
        // }
        if (Boolean.TRUE.equals(model.isBrandCodeToNull())) {
            changed = true;
            newer.setBrandCodeToNull(true); // 品牌ID更新为空值
        }
        if (Boolean.TRUE.equals(model.isModelNumberToNull())) {
            changed = true;
            newer.setModelNumberToNull(true); // 型号更新为空值
        }
        if (Boolean.TRUE.equals(model.isNameToNull())) {
            changed = true;
            newer.setNameToNull(true); // 商品名称更新为空值
        }
        if (Boolean.TRUE.equals(model.isTitleToNull())) {
            changed = true;
            newer.setTitleToNull(true); // 标题更新为空值
        }
        if (Boolean.TRUE.equals(model.isUnitToNull())) {
            changed = true;
            newer.setUnitToNull(true); // 单位(个/件/台/袋等)更新为空值
        }
        if (Boolean.TRUE.equals(model.isImageInfoToNull())) {
            changed = true;
            newer.setImageInfoToNull(true); // 图片信息更新为空值
        }
        if (Boolean.TRUE.equals(model.isMarketPriceTextToNull())) {
            changed = true;
            newer.setMarketPriceTextToNull(true); // 市场价格描述更新为空值
        }
        if (Boolean.TRUE.equals(model.isSalesPriceTextToNull())) {
            changed = true;
            newer.setSalesPriceTextToNull(true); // 销售价格描述(用于主商品展示的价格描述, 如80~99,199起)更新为空值
        }
        if (Boolean.TRUE.equals(model.isPriceValueToNull())) {
            changed = true;
            newer.setPriceValueToNull(true); // 价格值(实际售价)更新为空值
        }
        // if (VerifyTools.isNotBlank(model.getPriceValueAdd()) && model.getPriceValueAdd() != 0) {
        //     changed = true;
        //     newer.setPriceValueAdd(model.getPriceValueAdd()); // 价格值(实际售价)的增加值
        // }
        // if (Boolean.TRUE.equals(model.isSalesQuantityTotalToNull())) {
        //     changed = true;
        //     newer.setSalesQuantityTotalToNull(true); // 总销量更新为空值
        // }
        // if (VerifyTools.isNotBlank(model.getSalesQuantityTotalAdd()) && model.getSalesQuantityTotalAdd() != 0) {
        //     changed = true;
        //     newer.setSalesQuantityTotalAdd(model.getSalesQuantityTotalAdd()); // 总销量的增加值
        // }
        // if (Boolean.TRUE.equals(model.isStockQuantityToNull())) {
        //     changed = true;
        //     newer.setStockQuantityToNull(true); // 库存量更新为空值
        // }
        // if (VerifyTools.isNotBlank(model.getStockQuantityAdd()) && model.getStockQuantityAdd() != 0) {
        //     changed = true;
        //     newer.setStockQuantityAdd(model.getStockQuantityAdd()); // 库存量的增加值
        // }
        if (Boolean.TRUE.equals(model.isIntroTextToNull())) {
            changed = true;
            newer.setIntroTextToNull(true); // 摘要更新为空值
        }
        if (Boolean.TRUE.equals(model.isDescDetailsToNull())) {
            changed = true;
            newer.setDescDetailsToNull(true); // 详细描述(富文本)更新为空值
        }
        // if (Boolean.TRUE.equals(model.isSortIndexToNull())) {
        //     changed = true;
        //     newer.setSortIndexToNull(true); // 排序号更新为空值
        // }
        if (VerifyTools.isNotBlank(model.getSortIndexAdd()) && model.getSortIndexAdd() != 0) {
            changed = true;
            newer.setSortIndexAdd(model.getSortIndex()); // 排序号的增加值
        }
        // if (Boolean.TRUE.equals(model.isSpecificKindIdToNull())) {
        //     changed = true;
        //     newer.setSpecificKindIdToNull(true); // 规格分类ID更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isSpecificKindDataToNull())) {
        //     changed = true;
        //     newer.setSpecificKindDataToNull(true); // 规格数据列表(GoodsSpecificKind)更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isSkuInstanceDataToNull())) {
        //     changed = true;
        //     newer.setSkuInstanceDataToNull(true); // 单品实例列表(SkuSpecificInstance)更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isCreatorIdToNull())) {
        //     changed = true;
        //     newer.setCreatorIdToNull(true); // 创建人ID更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isPublishTimeToNull())) {
        //     changed = true;
        //     newer.setPublishTimeToNull(true); // 发布时间更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isPublishTimeToCurrent())) {
        //     changed = true;
        //     newer.setPublishTimeToCurrent(true); // 发布时间更新为数据库当前时间
        // }
        // if (VerifyTools.isNotBlank(model.getPublishTimeAdd()) && model.getPublishTimeAdd() != 0) {
        //     changed = true;
        //     newer.setPublishTimeAdd(model.getPublishTimeAdd()); // 发布时间的增加值
        // }
        // if (Boolean.TRUE.equals(model.isExpireTimeToNull())) {
        //     changed = true;
        //     newer.setExpireTimeToNull(true); // 过期时间更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isExpireTimeToCurrent())) {
        //     changed = true;
        //     newer.setExpireTimeToCurrent(true); // 过期时间更新为数据库当前时间
        // }
        // if (VerifyTools.isNotBlank(model.getExpireTimeAdd()) && model.getExpireTimeAdd() != 0) {
        //     changed = true;
        //     newer.setExpireTimeAdd(model.getExpireTimeAdd()); // 过期时间的增加值
        // }
        if (Boolean.TRUE.equals(model.isOptionsToNull())) {
            changed = true;
            newer.setOptionsToNull(true); // 选项更新为空值
        }
        // if (Boolean.TRUE.equals(model.isSubmitDescToNull())) {
        //     changed = true;
        //     newer.setSubmitDescToNull(true); // 提交说明更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isEditIndexToNull())) {
        //     changed = true;
        //     newer.setEditIndexToNull(true); // 编辑序号(每编辑一次递增1)更新为空值
        // }
        // if (VerifyTools.isNotBlank(model.getEditIndexAdd()) && model.getEditIndexAdd() != 0) {
        //     changed = true;
        //     newer.setEditIndexAdd(model.getEditIndexAdd()); // 编辑序号(每编辑一次递增1)的增加值
        // }
        // if (Boolean.TRUE.equals(model.isGoodsStateToNull())) {
        //     changed = true;
        //     newer.setGoodsStateToNull(true); // 商品状态(0.未提交|1.已提交|2.已审核|3.已驳回|4.已上架|5.已下架)更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isVersionStateToNull())) {
        //     changed = true;
        //     newer.setVersionStateToNull(true); // 版本状态(0.正本|1.副本|2.归档)更新为空值
        // }
        // if (Boolean.TRUE.equals(model.isQueryKeywordsToNull())) {
        //     changed = true;
        //     newer.setQueryKeywordsToNull(true); // 查询关键字更新为空值
        // }

        return changed ? newer : null;

    }

}
